/** 
 * @file        e2prom.c
 * @brief       
 * @details     
 * @author   fulong
 * @date     Mar 29, 2014
 * @version  1.0
 * @par Copyright (c):
 *       GPLv2
 */

#include "e2prom.h"
#include "../dev/i2c.h"
#include "../dev/uart.h"

/** @brief 代码目前支持的芯片，不能同时跟AT2404同在 */
//#define AT24C256
/** @brief 代码目前支持的芯片，不能同时跟AT24256同在 */
#define AT24C04
/** @brief 器件在总线上的地址 */
#define AT24CXXX_SLAVE_ADRESS 0x0
/** @brief AT24系列产品的固有代码 */
#define AT24CXXX_CODE 0xA0

/** @brief e2prom的从地址 */
#define AT_SLAVE_ADRESS (AT24CXXX_CODE | (AT24CXXX_SLAVE_ADRESS<<1))

/** @brief e2prom片选函数使用的控制宏，这个代表对芯片进行写操作 */
#define WRITE 0
/** @brief e2prom片选函数使用的控制宏，这个代表对芯片进行读操作 */
#define READ 1

/**
 * @breif 初始化e2prom的管教
 * @see
 * @return
 * @note 这个初始化貌似移植性貌似不是很高
 */
void e2prom_init(void) {
    i2c_io_init();
    i2c_stop();
}
/**
 * @breif e2prom的片选函数
 * @param adress e2prom器件的内部逻辑地址，即是代表里面存储单元的地址
 * @param control 表示将以什么方式片选这个e2prom.
 * @see i2c_start
 * @see WRITE
 * @see READ
 * @return
 * @note
 */
static void e2prom_chip_select(uint16 adress, uint8 control) {
    uint8 low_adr;
#ifdef AT24C256
	uint8 high_adr;
    high_adr = (adress >> 8);
#endif
    low_adr = (uint8)adress;
    i2c_start();
    i2c_send_byte(AT_SLAVE_ADRESS | control);
    recieve_ACK();
#ifdef AT24C256
    i2c_send_byte(high_adr);
    recieve_ACK();
#endif
    i2c_send_byte(low_adr);
    recieve_ACK();
}
/**
 * @breif e2prom发送单字节
 * @param adress 器件内部逻辑地址
 * @param data 要写入的数据
 * @see e2prom_chip_select
 * @see i2c_send_byte
 * @see recieve_ACK
 * @see i2c_stop
 * @return
 * @note
 */

void e2prom_write_single_byte(uint16 adress, uint8 data) {
    e2prom_chip_select(adress, WRITE);
    i2c_send_byte(data);
    recieve_ACK();
    i2c_stop();
}
/**
 * @breif e2prom发送单字节
 * @param adress 器件内部逻辑地址
 * @param data 要写入的数据缓冲区
 * @param length 数据缓冲区的长度
 * @see e2prom_chip_select
 * @see i2c_send_byte
 * @see recieve_ACK
 * @see i2c_stop
 * @return
 * @note 1.为什么要设定这个缓冲区，不设定一个结束标志位----因为任何一个字节都有可能作为数据写入，哪怕0也有可能是，所以不能设定结束位。\n
 */
uint8 e2prom_multiple_write(uint16 adress, uint8 *data, uint8 length) {
    uint8 len;
    //最长一次写入63个字节
    if (length > 63) return 0xFF;
    e2prom_chip_select(adress, WRITE);
    for (len = 0; len < length; len++) {
        i2c_send_byte(*data);
        recieve_ACK();
        data++;
    }
    i2c_stop();
    return len;
}
uint8 e2prom_read_random_byte(uint16 adress) {
    uint8 data;
    e2prom_chip_select(adress, WRITE);
    i2c_start();
    i2c_send_byte(AT_SLAVE_ADRESS | READ);
    ack_status += recieve_ACK();
    data = i2c_receive_byte();
    i2c_sendACK(1);
    i2c_stop();
    return data;
}
uint8 e2prom_multiple_read(uint16 adress, uint8 *data, uint8 length) {
    uint8 len;
    if (length > 63) return 0xFF;
    e2prom_chip_select(adress, WRITE);
    i2c_start();
    i2c_send_byte(AT_SLAVE_ADRESS | READ);
    recieve_ACK();
    for (len = 0; len < length; len++) {
        *data = i2c_receive_byte();
        data++;
        i2c_sendACK(0);
    }
    i2c_sendACK(1);
    i2c_stop();
    return len;
}
uint8 e2prom_read_cur_byte() {
    uint8 data;
    i2c_start();
    i2c_send_byte(AT_SLAVE_ADRESS | READ);
    recieve_ACK();
    data = i2c_receive_byte();
    i2c_sendACK(1);
    i2c_stop();
    return data;
}
uint8 get_e2prom_ack(void) {
    return ack_status;
}
